package com.aqs;


import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * 邮戳锁
 * <p>
 * 三种模式
 * 1.	Reading（读悲观模式）：功能和ReentrantLockReadWriteLock的读锁类似（读的时候不能写）
 * 2.	Wrting（写悲观模式）：功能和ReentrantLockReadWriteLock的读锁类似
 * 3.	Optimistic reading（乐观读模式）：无锁机制，类似于数据库中的乐观锁。支持并发读写，很乐观的认为读取时没人修改，只有当写的时候才升级为悲观模式
 *
 * @author xudong
 */
public class StampedLockDemo {

	Logger log = LoggerFactory.getLogger(StampedLockDemo.class);

	static int number = 30;

	static StampedLock stampedLock = new StampedLock();

	/**
	 *
	 */
	public void write() {
		System.out.println("写线程开始");

		long stamp = stampedLock.writeLock();
		System.out.println(Thread.currentThread().getName() + " ==" + "写线程修改准备");
		number = number + 13;
		stampedLock.unlock(stamp);
		System.out.println(Thread.currentThread().getName() + " ==" + "写线程修改结束");
	}

	/**
	 *
	 */
	public void read() {
		long stamp = stampedLock.readLock();
		System.out.println(Thread.currentThread().getName() + " ==" + "读线程准备");

		for (int i = 0; i < 4; i++) {
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
			System.out.println(Thread.currentThread().getName() + " 正在读取中");
		}
		System.out.println(Thread.currentThread().getName() + "读线程读取到值:" + number);
		System.out.println(Thread.currentThread().getName() + " ==" + "读线程结束");
		stampedLock.unlock(stamp);
	}

	/**
	 * 乐观读
	 */
	public void tryOptimisticRead() {
		long stamp = stampedLock.tryOptimisticRead();
		int result = number;
		System.out.println("4秒前 stampedLock.validate方法值（true 无修改 false有修改）" + "\t" + stampedLock.validate(stamp));
		for (int i = 0; i < 4; i++) {
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
			System.out.println(Thread.currentThread().getName() + "\t" + " 正在读取...." + i + "秒后" + "stampedLock.validate方法值（true 无修改 false有修改）" + "\t" + stampedLock.validate(stamp));
		}
		if (!stampedLock.validate(stamp)) {
			System.out.println("有人修改----------有写操作");
			stamp = stampedLock.readLock();
			try {
				System.out.println("从乐观读升级为悲观读");
				result = number;
				System.out.println("重新悲观读后result：" + result);
			} finally {
				stampedLock.unlockRead(stamp);
			}
		}
		System.out.println(Thread.currentThread().getName() + "\t" + "finally value: " + result);
	}

	public static void main(String[] args) {
		// test1();
		test2();

	}

	/**
	 * 测试传统的读
	 */
	public static void test1() {

		StampedLockDemo stampedLockDemo = new StampedLockDemo();
		new Thread(stampedLockDemo::read, "read Thread").start();

		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}

		new Thread(stampedLockDemo::write, "write thread").start();
	}

	/**
	 * 测试乐观读
	 */
	public static void test2() {
		StampedLockDemo stampedLockDemo = new StampedLockDemo();

		new Thread(stampedLockDemo::tryOptimisticRead, "readThread").start();
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
		new Thread(stampedLockDemo::write, "writeThread").start();
	}


}
